package doweb

import (
	// "encoding/json"
	"fmt"
	"manygo/dohttp"
	"manygo/mytools"

	"github.com/valyala/fasthttp"
	"manygo/rabbitmq"

	"time"
)

//Inf 统计一个客户端的状态
type Inf struct {
	IP string
	//ID      string
	Time    int64
	Status  bool
	IsAlive bool
}

//AliveStatus 统计当前运行的客户端和并发数
type AliveStatus struct {
	Anum   int
	Rnum   int
	IPList []string
	cha    chan int
}

//AllData 记录运行状态
type AllData struct {
	AvgTime           int64
	AvgSuccessTime    int64
	MiddleTime        int64
	MiddleSuccessTime int64
	AllNum            int
	SuccessNum        int
	FailedNum         int
	StartTime         int64
	AllSend           int64
	Allrecv           int64
	allTime           int64
	nowNum            int
	successTime       int64
	MinTime           int64
	MaxTime           int64
	allTimeList       []int64
	successTimeList   []int64
	NowTime           int64
	QPS               float64
}

//RData 用于记录整理后的数组结构
type RData struct {
	RunNum     int
	AvgTime    int64
	MiddleTime int64
	AllNum     int
	SuccessNum int
	FailedNum  int
	AllSend    int64
	Allrecv    int64
	QPS        float64
}

//SData 单个秒的记录数据
type SData struct {
	AllNum          int
	SuccessNum      int
	FailedNum       int
	AllSend         int64
	Allrecv         int64
	AllTime         int64
	SuccessTime     int64
	AllTimeList     []int64
	SuccessTimeList []int64
}

//RunnerNumMap 记录并发数的每一秒的记录
var RunnerNumMap map[int64]int

//RDataMap 记录整理完成后的每秒数据
var RDataMap map[int64]*RData

// TimeMap 记录未整理前收到的数据
var TimeMap map[int64]*SData

//FailedMap 记录错误的内容和数量
var FailedMap map[string]int

//TimeChan 记录当前未整理的时间通道
var TimeChan chan int64

//AliveTable 记录客户端的列表
var AliveTable map[string]*Inf

//AliveStatusVar AliveStatus的参数
var AliveStatusVar *AliveStatus

//AllDataVar AllData实际值
var AllDataVar *AllData

//DataAnaly 分析受到的数据
func DataAnaly() {
	for {
		select {
		case i := <-TimeChan:
			// rwlock.Lock()
			time.Sleep(time.Second)
			rrt := time.Now()
			if v, ok := TimeMap[i]; ok {
				//AllDataVar
				AllDataVar.AllNum += v.AllNum
				AllDataVar.nowNum += v.AllNum
				AllDataVar.AllSend += v.AllSend
				AllDataVar.Allrecv += v.Allrecv
				AllDataVar.SuccessNum += v.SuccessNum
				AllDataVar.FailedNum += v.FailedNum
				AllDataVar.allTime += v.AllTime
				AllDataVar.successTime += v.SuccessTime
				AllDataVar.NowTime = i
				AllDataVar.AvgTime = AllDataVar.allTime / int64(AllDataVar.AllNum)
				if AllDataVar.SuccessNum != 0 {
					AllDataVar.AvgSuccessTime = AllDataVar.successTime / int64(AllDataVar.SuccessNum)
				}

				// RDataMap
				RDataMap[i] = new(RData)
				RDataMap[i].AllSend = v.AllSend
				RDataMap[i].Allrecv = v.Allrecv
				RDataMap[i].SuccessNum = v.SuccessNum
				RDataMap[i].AllNum = v.AllNum
				RDataMap[i].FailedNum = v.FailedNum
				if v2, ok2 := RunnerNumMap[i]; ok2 {
					RDataMap[i].RunNum = v2
				} else {
					RDataMap[i].RunNum = 0
				}
				RDataMap[i].AvgTime = AllDataVar.AvgTime
				if RDataMap[i].RunNum == 0 {
					AllDataVar.QPS = 0

				} else {
					fmt.Println(v.AllNum, AllDataVar.nowNum, i-AllDataVar.StartTime, RDataMap[i].RunNum)
					tt := int64(1)
					if i-AllDataVar.StartTime != 0 {
						tt = i - AllDataVar.StartTime
					}

					AllDataVar.QPS = float64(AllDataVar.nowNum) / float64(tt) / float64(RDataMap[i].RunNum)

				}
				RDataMap[i].QPS = AllDataVar.QPS

				for _, i2 := range v.AllTimeList {
					if i2 > AllDataVar.MaxTime {
						AllDataVar.MaxTime = i2
					}
					if i2 < AllDataVar.MinTime {
						AllDataVar.MinTime = i2
					}
					if len(AllDataVar.allTimeList) == 0 || AllDataVar.MaxTime == i2 {
						AllDataVar.allTimeList = append(AllDataVar.allTimeList, i2)
					} else {
						n := localList(AllDataVar.allTimeList, i2)
						if n == 0 {
							AllDataVar.allTimeList = append([]int64{i2}, AllDataVar.allTimeList...)
						} else {
							tmpList := AllDataVar.allTimeList[n:]
							AllDataVar.allTimeList = append(AllDataVar.allTimeList[:n-1], i2)
							AllDataVar.allTimeList = append(AllDataVar.allTimeList, tmpList...)
						}
						// if AllDataVar.MinTime == i2{
						// 	AllDataVar.allTimeList=append([]int64{i2},AllDataVar.allTimeList)
						// }
					}

				}
				for _, i2 := range v.SuccessTimeList {
					v00 := len(AllDataVar.successTimeList)
					if v00 == 0 || AllDataVar.successTimeList[v00-1] <= i2 {
						AllDataVar.successTimeList = append(AllDataVar.successTimeList, i2)
					} else {
						n := localList(AllDataVar.successTimeList, i2)
						if n == 0 {
							AllDataVar.successTimeList = append([]int64{i2}, AllDataVar.successTimeList...)
						} else {
							tmpList := AllDataVar.successTimeList[n:]
							AllDataVar.successTimeList = append(AllDataVar.successTimeList[:n-1], i2)
							AllDataVar.successTimeList = append(AllDataVar.successTimeList, tmpList...)
						}
						// if AllDataVar.MinTime == i2{
						// 	AllDataVar.allTimeList=append([]int64{i2},AllDataVar.allTimeList)
						// }
					}

				}

				// middletime
				AllDataVar.MiddleTime = AllDataVar.allTimeList[len(AllDataVar.allTimeList)/2]
				if len(AllDataVar.successTimeList) != 0 {
					AllDataVar.MiddleSuccessTime = AllDataVar.successTimeList[len(AllDataVar.successTimeList)/2]
					RDataMap[i].MiddleTime = AllDataVar.MiddleTime
				}

				fmt.Println(AllDataVar.QPS)

			}
			fmt.Println(i, time.Since(rrt))
			delete(TimeMap, i)
			// else {
			// 	fmt.Println("no ddd")
			// }
			// rwlock.Unlock()
		}
	}

}

// localList 定位列表
func localList(l []int64, num int64) int {
	// fmt.Println(l, num)
	// rwlock.Lock()
	v0 := len(l)
	// v1 := v0 / 100
	// m1 := v0 % 100
	l2 := make([]int64, 0)
	if v0 <= 100 {

		for ind, n := range l {
			if num <= n {
				return ind
			}
		}

	}
	if v0 <= 5000 {
		l2 = append(l2, l[0])
		for i3 := 100; i3 < v0; i3 += 100 {
			l2 = append(l2, l[i3-1])
			l2 = append(l2, l[i3])

		}
		l2 = append(l2, l[v0-1])
		v2 := localList(l2, num) / 2
		v22 := v0
		if v2*100+100 < v0 {
			v22 = v2*100 + 100
		}
		return localList(l[v2*100:v22], num) + v2*100

	}
	l2 = append(l2, l[0])
	for i3 := 5000; i3 < v0; i3 += 5000 {
		l2 = append(l2, l[i3-1])
		l2 = append(l2, l[i3])

	}
	l2 = append(l2, l[v0-1])
	v2 := localList(l2, num) / 2
	v22 := v0
	if v2*5000+5000 < v0 {
		v22 = v2*5000 + 5000
	}
	// fmt.Println(111, v2, v22, v0)
	return localList(l[v2*5000:v22], num) + v2*5000

}

//HeartBeatAdd 心跳添加
func HeartBeatAdd(ctx *fasthttp.RequestCtx) {
	ip := ClientIP(ctx)

	if _, ok := AliveTable[ip]; ok {
		AliveTable[ip].IsAlive = true

		AliveTable[ip].Time = time.Now().Unix()

	} else {
		if !ok {
			AliveTable[ip] = &Inf{ip, time.Now().Unix(), false, true}
		}

	}

	fmt.Fprint(ctx, ip)

}

//HeartBeatConnect 心跳
func HeartBeatConnect(ctx *fasthttp.RequestCtx) {
	ip := ClientIP(ctx)
	die := 0
	// fmt.Println(ip)

	if v, ok := AliveTable[ip]; ok {
		// AliveTable[ip].isAlive = true
		if v.IsAlive {
			AliveTable[ip].Time = time.Now().Unix()
			fmt.Fprint(ctx, "ok")
		} else {
			fmt.Fprint(ctx, "no")
		}

	} else {
		die++

		fmt.Fprint(ctx, "no")
	}
	if die > 0 {

		ReTask(AliveStatusVar.Rnum)
	}

}

//HeartBeatRemove 心跳移除
func HeartBeatRemove(ctx *fasthttp.RequestCtx) {
	ip := ClientIP(ctx)
	delete(AliveTable, ip)
	fmt.Fprint(ctx, "")
}

//CheckTask 给客户端添加运行前准备
func CheckTask(ii *Inf) {
	_, err := dohttp.SamplePostJSON("http://"+ii.IP+":9989/checktask", []byte("ok"))
	if err != nil {
		fmt.Println(err)
	}
	ii.Status = true
	AllDataVar.StartTime = time.Now().Unix()
	ReTask(AliveStatusVar.Rnum)

}

//HeartBeatWork 添加定时校验客户端的任务
func HeartBeatWork(t time.Duration) {
	for {
		ips := make([]string, 0)

		time.Sleep(t * time.Second)
		t1 := time.Now().Unix()
		for k, v := range AliveTable {
			if t1-v.Time > 3 {
				AliveTable[k].IsAlive = false
			} else {
				if AliveTable[k].IsAlive {
					if AliveTable[k].Status {
						ips = append(ips, v.IP)
					} else {
						go CheckTask(AliveTable[k])
					}

				}

			}
		}
		AliveStatusVar.IPList = ips
		if len(ips) != AliveStatusVar.Anum {
			AliveStatusVar.Anum = len(ips)
			AliveStatusVar.cha <- len(ips)
		}

	}

}

//ManageMasterTask 分配并发数到客户端
func ManageMasterTask() {
	for {
		select {
		case <-AliveStatusVar.cha:
			rein, ok := AvgClient(AliveStatusVar.Anum, AliveStatusVar.Rnum)
			// fmt.Println(rein)
			if ok {
				AllDataVar.StartTime = time.Now().Unix()
				AllDataVar.nowNum = 0
				for i := 0; i < AliveStatusVar.Anum; i++ {

					v, err := dohttp.SampleGet("http://" + AliveStatusVar.IPList[i] + ":9989/settask?num=" + mytools.Int2String(rein[i]))
					if err != nil || v == "no" {
						AliveTable[AliveStatusVar.IPList[i]].IsAlive = false
						defer ReTask(AliveStatusVar.Rnum)
						break

					}

				}
			}

		}

	}
}

//AvgClient 计算对应客户端的分摊数，后期可优化
func AvgClient(Cnum int, Rnum int) ([]int, bool) {
	rein := make([]int, 0)
	if Cnum == 0 {
		return rein, false
	}
	avg := Rnum / Cnum
	mod := Rnum % Cnum

	for i := 0; i < Cnum; i++ {
		if i < mod {
			rein = append(rein, avg+1)
		} else {
			rein = append(rein, avg)
		}

	}
	// fmt.Println(avg, mod, rein, Rnum, Cnum)
	return rein, true
}

//HeartBeatGet 获取心跳客户端
func HeartBeatGet(ctx *fasthttp.RequestCtx) {
	fmt.Fprint(ctx, mytools.Struct2String(AliveTable))

}

//AllDataGet 获得当前数据
func AllDataGet(ctx *fasthttp.RequestCtx) {
	fmt.Fprint(ctx, mytools.Struct2String(AllDataVar))

}

//MasterStart 开始运行
func MasterStart() {
	rmq = rabbitmq.NewRabbitMQSimple("mqtby", "admin", "admin", "192.168.56.115", "5672", "/")
	if rmq == nil {
		panic("连接mq失败")
	}
	AliveTable = make(map[string]*Inf)
	RunnerNumMap = make(map[int64]int)
	TimeMap = make(map[int64]*SData)
	FailedMap = make(map[string]int)
	TimeChan = make(chan int64, 1)
	AliveStatusVar = new(AliveStatus)
	AliveStatusVar.cha = make(chan int, 4)
	AllDataVar = new(AllData)
	AllDataVar.successTimeList = make([]int64, 0)
	AllDataVar.allTimeList = make([]int64, 0)
	AllDataVar.MinTime = 999999999
	AllDataVar.StartTime = time.Now().Unix()
	RDataMap = make(map[int64]*RData)

	go HeartBeatWork(2)
	go ManageMasterTask()
	// go SecondTime()
	// go DataAnaly()

	go GetMQ(HandleString)

	fmt.Println("当前机器的ip地址有：")
	for _, ip := range mytools.MyIP() {
		fmt.Println(ip)
	}
	fmt.Println("Master is running...Please open:")
	fmt.Println("http://127.0.0.1:9988/index")
	AddRouter("GET", "/", Index)
	AddRouter("GET", "/heartbeatadd", HeartBeatAdd)
	AddRouter("GET", "/heartbeatconnect", HeartBeatConnect)
	AddRouter("GET", "/heartbeatget", HeartBeatGet)
	AddRouter("GET", "/heartbeatremove", HeartBeatRemove)
	AddRouter("GET", "/settasks", SetTasks)
	AddRouter("GET", "/alldataget", AllDataGet)

	Start("9988")

}

//ReTask 13
func ReTask(i int) bool {
	f := make([]string, 0)
	for _, v := range AliveTable {
		if v.Status && v.IsAlive {
			f = append(f, v.IP)
			// dohttp.SampleGet("http://" + v.IP + ":9989/settask?num=" + string(ctx.FormValue("num")))
		}

	}
	if len(f) == 0 {

		return false
	}

	if i <= 0 {
		i = 0
	}

	AliveStatusVar.IPList = f
	AliveStatusVar.Anum = len(f)
	AliveStatusVar.Rnum = i
	AliveStatusVar.cha <- i
	return true
}

//SetTasks 设置并发数
func SetTasks(ctx *fasthttp.RequestCtx) {

	i, err := mytools.String2Int(string(ctx.FormValue("num")))
	// i todo
	if err != nil {
		fmt.Fprint(ctx, err.Error())
		return
	}
	if ReTask(i) {
		fmt.Fprint(ctx, "ok")
	} else {
		fmt.Fprint(ctx, "无可运行的实例")
	}
	// if len(AliveTable) == 0 {
	// 	fmt.Fprint(ctx, "no Client")
	// 	return
	// }

}

//GetMQ 123
func GetMQ(f func(interface{})) {
	for v := range rmq.ConsumeSimple() {
		v1 := Result{}
		// fmt.Println(v.Body)
		mytools.Binary2Struct(v.Body, &v1)
		f(v1)

	}
}

//HandleString 123
func HandleString(v interface{}) {
	fmt.Printf("%+v\n", v)
	s, _ := v.(Result)

}
